home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / test / glpuzzle.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-25  |  30.4 KB  |  1,484 lines

  1. //
  2. // "$Id: glpuzzle.cxx,v 1.8 1999/02/25 20:05:30 bill Exp $"
  3. //
  4. // OpenGL puzzle demo for the Fast Light Tool Kit (FLTK).
  5. //
  6. // This is a GLUT demo program to demonstrate fltk's GLUT emulation.
  7. // Search for "fltk" to find all the changes
  8. //
  9. // Copyright 1998-1999 by Bill Spitzak and others.
  10. //
  11. // This library is free software; you can redistribute it and/or
  12. // modify it under the terms of the GNU Library General Public
  13. // License as published by the Free Software Foundation; either
  14. // version 2 of the License, or (at your option) any later version.
  15. //
  16. // This library is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19. // Library General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU Library General Public
  22. // License along with this library; if not, write to the Free Software
  23. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  24. // USA.
  25. //
  26. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  27. //
  28.  
  29. // this block added for fltk's distribtion so it will compile w/o OpenGL:
  30. #include <config.h>
  31. #if !HAVE_GL
  32. #include <FL/Fl.H>
  33. #include <FL/fl_message.H>
  34. int main(int, char**) {
  35.   fl_alert("This demo does not work without GL");
  36.   return 1;
  37. }
  38. #else
  39. // end of added block
  40.  
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #include <time.h>
  46. #include <math.h>
  47. #include <FL/glut.H>    // changed for fltk
  48. #include "trackball.c"    // changed from trackball.h for fltk
  49.  
  50. #define WIDTH 4
  51. #define HEIGHT 5
  52. #define PIECES 10
  53. #define OFFSETX -2
  54. #define OFFSETY -2.5
  55. #define OFFSETZ -0.5
  56.  
  57. typedef char Config[HEIGHT][WIDTH];
  58.  
  59. struct puzzle {
  60.   struct puzzle *backptr;
  61.   struct puzzle *solnptr;
  62.   Config pieces;
  63.   struct puzzle *next;
  64.   unsigned hashvalue;
  65. };
  66.  
  67. #define HASHSIZE 10691
  68.  
  69. struct puzzlelist {
  70.   struct puzzle *puzzle;
  71.   struct puzzlelist *next;
  72. };
  73.  
  74. static char convert[PIECES + 1] =
  75. {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};
  76.  
  77. static unsigned char colors[PIECES + 1][3] =
  78. {
  79.   {0, 0, 0},
  80.   {255, 255, 127},
  81.   {255, 255, 127},
  82.   {255, 255, 127},
  83.   {255, 255, 127},
  84.   {255, 127, 255},
  85.   {255, 127, 255},
  86.   {255, 127, 255},
  87.   {255, 127, 255},
  88.   {255, 127, 127},
  89.   {255, 255, 255},
  90. };
  91.  
  92. void changeState(void);
  93.  
  94. static struct puzzle *hashtable[HASHSIZE];
  95. static struct puzzle *startPuzzle;
  96. static struct puzzlelist *puzzles;
  97. static struct puzzlelist *lastentry;
  98.  
  99. int curX, curY, visible;
  100.  
  101. #define MOVE_SPEED 0.2
  102. static unsigned char movingPiece;
  103. static float move_x, move_y;
  104. static float curquat[4];
  105. static int doubleBuffer = 1;
  106. static int depth = 1;
  107.  
  108. static char xsize[PIECES + 1] =
  109. {0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2};
  110. static char ysize[PIECES + 1] =
  111. {0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2};
  112. static float zsize[PIECES + 1] =
  113. {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.6};
  114.  
  115. static Config startConfig =
  116. {
  117.   {8, 10, 10, 7},
  118.   {8, 10, 10, 7},
  119.   {6, 9, 9, 5},
  120.   {6, 4, 3, 5},
  121.   {2, 0, 0, 1}
  122. };
  123.  
  124. static Config thePuzzle =
  125. {
  126.   {8, 10, 10, 7},
  127.   {8, 10, 10, 7},
  128.   {6, 9, 9, 5},
  129.   {6, 4, 3, 5},
  130.   {2, 0, 0, 1}
  131. };
  132.  
  133. static int xadds[4] =
  134. {-1, 0, 1, 0};
  135. static int yadds[4] =
  136. {0, -1, 0, 1};
  137.  
  138. static long W = 400, H = 300;
  139. static GLint viewport[4];
  140.  
  141. #define srandom srand
  142. #define random() (rand() >> 2)
  143.  
  144. unsigned
  145. hash(Config config)
  146. {
  147.   int i, j, value;
  148.  
  149.   value = 0;
  150.   for (i = 0; i < HEIGHT; i++) {
  151.     for (j = 0; j < WIDTH; j++) {
  152.       value = value + convert[config[i][j]];
  153.       value *= 6;
  154.     }
  155.   }
  156.   return (value);
  157. }
  158.  
  159. int
  160. solution(Config config)
  161. {
  162.   if (config[4][1] == 10 && config[4][2] == 10)
  163.     return (1);
  164.   return (0);
  165. }
  166.  
  167. float boxcoords[][3] =
  168. {
  169.   {0.2, 0.2, 0.9},
  170.   {0.8, 0.2, 0.9},
  171.   {0.8, 0.8, 0.9},
  172.   {0.2, 0.8, 0.9},
  173.   {0.2, 0.1, 0.8},
  174.   {0.8, 0.1, 0.8},
  175.   {0.9, 0.2, 0.8},
  176.   {0.9, 0.8, 0.8},
  177.   {0.8, 0.9, 0.8},
  178.   {0.2, 0.9, 0.8},
  179.   {0.1, 0.8, 0.8},
  180.   {0.1, 0.2, 0.8},
  181.   {0.2, 0.1, 0.2},
  182.   {0.8, 0.1, 0.2},
  183.   {0.9, 0.2, 0.2},
  184.   {0.9, 0.8, 0.2},
  185.   {0.8, 0.9, 0.2},
  186.   {0.2, 0.9, 0.2},
  187.   {0.1, 0.8, 0.2},
  188.   {0.1, 0.2, 0.2},
  189.   {0.2, 0.2, 0.1},
  190.   {0.8, 0.2, 0.1},
  191.   {0.8, 0.8, 0.1},
  192.   {0.2, 0.8, 0.1},
  193. };
  194.  
  195. float boxnormals[][3] =
  196. {
  197.   {0, 0, 1},            /* 0 */
  198.   {0, 1, 0},
  199.   {1, 0, 0},
  200.   {0, 0, -1},
  201.   {0, -1, 0},
  202.   {-1, 0, 0},
  203.   {0.7071, 0.7071, 0.0000},  /* 6 */
  204.   {0.7071, -0.7071, 0.0000},
  205.   {-0.7071, 0.7071, 0.0000},
  206.   {-0.7071, -0.7071, 0.0000},
  207.   {0.7071, 0.0000, 0.7071},  /* 10 */
  208.   {0.7071, 0.0000, -0.7071},
  209.   {-0.7071, 0.0000, 0.7071},
  210.   {-0.7071, 0.0000, -0.7071},
  211.   {0.0000, 0.7071, 0.7071},  /* 14 */
  212.   {0.0000, 0.7071, -0.7071},
  213.   {0.0000, -0.7071, 0.7071},
  214.   {0.0000, -0.7071, -0.7071},
  215.   {0.5774, 0.5774, 0.5774},  /* 18 */
  216.   {0.5774, 0.5774, -0.5774},
  217.   {0.5774, -0.5774, 0.5774},
  218.   {0.5774, -0.5774, -0.5774},
  219.   {-0.5774, 0.5774, 0.5774},
  220.   {-0.5774, 0.5774, -0.5774},
  221.   {-0.5774, -0.5774, 0.5774},
  222.   {-0.5774, -0.5774, -0.5774},
  223. };
  224.  
  225. int boxfaces[][4] =
  226. {
  227.   {0, 1, 2, 3},         /* 0 */
  228.   {9, 8, 16, 17},
  229.   {6, 14, 15, 7},
  230.   {20, 23, 22, 21},
  231.   {12, 13, 5, 4},
  232.   {19, 11, 10, 18},
  233.   {7, 15, 16, 8},       /* 6 */
  234.   {13, 14, 6, 5},
  235.   {18, 10, 9, 17},
  236.   {19, 12, 4, 11},
  237.   {1, 6, 7, 2},         /* 10 */
  238.   {14, 21, 22, 15},
  239.   {11, 0, 3, 10},
  240.   {20, 19, 18, 23},
  241.   {3, 2, 8, 9},         /* 14 */
  242.   {17, 16, 22, 23},
  243.   {4, 5, 1, 0},
  244.   {20, 21, 13, 12},
  245.   {2, 7, 8, -1},        /* 18 */
  246.   {16, 15, 22, -1},
  247.   {5, 6, 1, -1},
  248.   {13, 21, 14, -1},
  249.   {10, 3, 9, -1},
  250.   {18, 17, 23, -1},
  251.   {11, 4, 0, -1},
  252.   {20, 12, 19, -1},
  253. };
  254.  
  255. #define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))
  256.  
  257. /* Draw a box.  Bevel as desired. */
  258. void
  259. drawBox(int piece, float xoff, float yoff)
  260. {
  261.   int xlen, ylen;
  262.   int i, k;
  263.   float x, y, z;
  264.   float zlen;
  265.   float *v;
  266.  
  267.   xlen = xsize[piece];
  268.   ylen = ysize[piece];
  269.   zlen = zsize[piece];
  270.  
  271.   glColor3ubv(colors[piece]);
  272.   glBegin(GL_QUADS);
  273.   for (i = 0; i < 18; i++) {
  274.     glNormal3fv(boxnormals[i]);
  275.     for (k = 0; k < 4; k++) {
  276.       if (boxfaces[i][k] == -1)
  277.         continue;
  278.       v = boxcoords[boxfaces[i][k]];
  279.       x = v[0] + OFFSETX;
  280.       if (v[0] > 0.5)
  281.         x += xlen - 1;
  282.       y = v[1] + OFFSETY;
  283.       if (v[1] > 0.5)
  284.         y += ylen - 1;
  285.       z = v[2] + OFFSETZ;
  286.       if (v[2] > 0.5)
  287.         z += zlen - 1;
  288.       glVertex3f(xoff + x, yoff + y, z);
  289.     }
  290.   }
  291.   glEnd();
  292.   glBegin(GL_TRIANGLES);
  293.   for (i = 18; i < int(NBOXFACES); i++) {
  294.     glNormal3fv(boxnormals[i]);
  295.     for (k = 0; k < 3; k++) {
  296.       if (boxfaces[i][k] == -1)
  297.         continue;
  298.       v = boxcoords[boxfaces[i][k]];
  299.       x = v[0] + OFFSETX;
  300.       if (v[0] > 0.5)
  301.         x += xlen - 1;
  302.       y = v[1] + OFFSETY;
  303.       if (v[1] > 0.5)
  304.         y += ylen - 1;
  305.       z = v[2] + OFFSETZ;
  306.       if (v[2] > 0.5)
  307.         z += zlen - 1;
  308.       glVertex3f(xoff + x, yoff + y, z);
  309.     }
  310.   }
  311.   glEnd();
  312. }
  313.  
  314. float containercoords[][3] =
  315. {
  316.   {-0.1, -0.1, 1.0},
  317.   {-0.1, -0.1, -0.1},
  318.   {4.1, -0.1, -0.1},
  319.   {4.1, -0.1, 1.0},
  320.   {1.0, -0.1, 0.6},     /* 4 */
  321.   {3.0, -0.1, 0.6},
  322.   {1.0, -0.1, 0.0},
  323.   {3.0, -0.1, 0.0},
  324.   {1.0, 0.0, 0.0},      /* 8 */
  325.   {3.0, 0.0, 0.0},
  326.   {3.0, 0.0, 0.6},
  327.   {1.0, 0.0, 0.6},
  328.   {0.0, 0.0, 1.0},      /* 12 */
  329.   {4.0, 0.0, 1.0},
  330.   {4.0, 0.0, 0.0},
  331.   {0.0, 0.0, 0.0},
  332.   {0.0, 5.0, 0.0},      /* 16 */
  333.   {0.0, 5.0, 1.0},
  334.   {4.0, 5.0, 1.0},
  335.   {4.0, 5.0, 0.0},
  336.   {-0.1, 5.1, -0.1},    /* 20 */
  337.   {4.1, 5.1, -0.1},
  338.   {4.1, 5.1, 1.0},
  339.   {-0.1, 5.1, 1.0},
  340. };
  341.  
  342. float containernormals[][3] =
  343. {
  344.   {0, -1, 0},
  345.   {0, -1, 0},
  346.   {0, -1, 0},
  347.   {0, -1, 0},
  348.   {0, -1, 0},
  349.   {0, 1, 0},
  350.   {0, 1, 0},
  351.   {0, 1, 0},
  352.   {1, 0, 0},
  353.   {1, 0, 0},
  354.   {1, 0, 0},
  355.   {-1, 0, 0},
  356.   {-1, 0, 0},
  357.   {-1, 0, 0},
  358.   {0, 1, 0},
  359.   {0, 0, -1},
  360.   {0, 0, -1},
  361.   {0, 0, 1},
  362.   {0, 0, 1},
  363.   {0, 0, 1},
  364.   {0, 0, 1},
  365.   {0, 0, 1},
  366.   {0, 0, 1},
  367.   {0, 0, 1},
  368. };
  369.  
  370. int containerfaces[][4] =
  371. {
  372.   {1, 6, 4, 0},
  373.   {0, 4, 5, 3},
  374.   {1, 2, 7, 6},
  375.   {7, 2, 3, 5},
  376.   {16, 19, 18, 17},
  377.  
  378.   {23, 22, 21, 20},
  379.   {12, 11, 8, 15},
  380.   {10, 13, 14, 9},
  381.  
  382.   {15, 16, 17, 12},
  383.   {2, 21, 22, 3},
  384.   {6, 8, 11, 4},
  385.  
  386.   {1, 0, 23, 20},
  387.   {14, 13, 18, 19},
  388.   {9, 7, 5, 10},
  389.  
  390.   {12, 13, 10, 11},
  391.  
  392.   {1, 20, 21, 2},
  393.   {4, 11, 10, 5},
  394.  
  395.   {15, 8, 19, 16},
  396.   {19, 8, 9, 14},
  397.   {8, 6, 7, 9},
  398.   {0, 3, 13, 12},
  399.   {13, 3, 22, 18},
  400.   {18, 22, 23, 17},
  401.   {17, 23, 0, 12},
  402. };
  403.  
  404. #define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))
  405.  
  406. /* Draw the container */
  407. void
  408. drawContainer(void)
  409. {
  410.   int i, k;
  411.   float *v;
  412.  
  413.   /* Y is reversed here because the model has it reversed */
  414.  
  415.   /* Arbitrary bright wood-like color */
  416.   glColor3ub(209, 103, 23);
  417.   glBegin(GL_QUADS);
  418.   for (i = 0; i < int(NCONTFACES); i++) {
  419.     v = containernormals[i];
  420.     glNormal3f(v[0], -v[1], v[2]);
  421.     for (k = 3; k >= 0; k--) {
  422.       v = containercoords[containerfaces[i][k]];
  423.       glVertex3f(v[0] + OFFSETX, -(v[1] + OFFSETY), v[2] + OFFSETZ);
  424.     }
  425.   }
  426.   glEnd();
  427. }
  428.  
  429. void
  430. drawAll(void)
  431. {
  432.   int i, j;
  433.   int piece;
  434.   char done[PIECES + 1];
  435.   float m[4][4];
  436.  
  437.   build_rotmatrix(m, curquat);
  438.   glMatrixMode(GL_MODELVIEW);
  439.   glLoadIdentity();
  440.   glTranslatef(0, 0, -10);
  441.   glMultMatrixf(&(m[0][0]));
  442.   glRotatef(180, 0, 0, 1);
  443.  
  444.   if (depth) {
  445.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  446.   } else {
  447.     glClear(GL_COLOR_BUFFER_BIT);
  448.   }
  449.   for (i = 1; i <= PIECES; i++) {
  450.     done[i] = 0;
  451.   }
  452.   glLoadName(0);
  453.   drawContainer();
  454.   for (i = 0; i < HEIGHT; i++) {
  455.     for (j = 0; j < WIDTH; j++) {
  456.       piece = thePuzzle[i][j];
  457.       if (piece == 0)
  458.         continue;
  459.       if (done[piece])
  460.         continue;
  461.       done[piece] = 1;
  462.       glLoadName(piece);
  463.       if (piece == movingPiece) {
  464.         drawBox(piece, move_x, move_y);
  465.       } else {
  466.         drawBox(piece, j, i);
  467.       }
  468.     }
  469.   }
  470. }
  471.  
  472. void
  473. redraw(void)
  474. {
  475.   glMatrixMode(GL_PROJECTION);
  476.   glLoadIdentity();
  477.   gluPerspective(45, viewport[2]*1.0/viewport[3], 0.1, 100.0);
  478.  
  479.   drawAll();
  480.  
  481.   if (doubleBuffer)
  482.     glutSwapBuffers();
  483.   else
  484.     glFinish();
  485. }
  486.  
  487. void
  488. solidifyChain(struct puzzle *puzzle)
  489. {
  490.   int i;
  491.   char buf[256];
  492.  
  493.   i = 0;
  494.   while (puzzle->backptr) {
  495.     i++;
  496.     puzzle->backptr->solnptr = puzzle;
  497.     puzzle = puzzle->backptr;
  498.   }
  499.   sprintf(buf, "%d moves to complete!", i);
  500.   glutSetWindowTitle(buf);
  501. }
  502.  
  503. int
  504. addConfig(Config config, struct puzzle *back)
  505. {
  506.   unsigned hashvalue;
  507.   struct puzzle *newpiece;
  508.   struct puzzlelist *newlistentry;
  509.  
  510.   hashvalue = hash(config);
  511.  
  512.   newpiece = hashtable[hashvalue % HASHSIZE];
  513.   while (newpiece != NULL) {
  514.     if (newpiece->hashvalue == hashvalue) {
  515.       int i, j;
  516.  
  517.       for (i = 0; i < WIDTH; i++) {
  518.         for (j = 0; j < HEIGHT; j++) {
  519.           if (convert[config[j][i]] !=
  520.             convert[newpiece->pieces[j][i]])
  521.             goto nomatch;
  522.         }
  523.       }
  524.       return 0;
  525.     }
  526.   nomatch:
  527.     newpiece = newpiece->next;
  528.   }
  529.  
  530.   newpiece = (struct puzzle *) malloc(sizeof(struct puzzle));
  531.   newpiece->next = hashtable[hashvalue % HASHSIZE];
  532.   newpiece->hashvalue = hashvalue;
  533.   memcpy(newpiece->pieces, config, HEIGHT * WIDTH);
  534.   newpiece->backptr = back;
  535.   newpiece->solnptr = NULL;
  536.   hashtable[hashvalue % HASHSIZE] = newpiece;
  537.  
  538.   newlistentry = (struct puzzlelist *) malloc(sizeof(struct puzzlelist));
  539.   newlistentry->puzzle = newpiece;
  540.   newlistentry->next = NULL;
  541.  
  542.   if (lastentry) {
  543.     lastentry->next = newlistentry;
  544.   } else {
  545.     puzzles = newlistentry;
  546.   }
  547.   lastentry = newlistentry;
  548.  
  549.   if (back == NULL) {
  550.     startPuzzle = newpiece;
  551.   }
  552.   if (solution(config)) {
  553.     solidifyChain(newpiece);
  554.     return 1;
  555.   }
  556.   return 0;
  557. }
  558.  
  559. /* Checks if a space can move */
  560. int
  561. canmove0(Config pieces, int x, int y, int dir, Config newpieces)
  562. {
  563.   char piece;
  564.   int xadd, yadd;
  565.   int l, m;
  566.  
  567.   xadd = xadds[dir];
  568.   yadd = yadds[dir];
  569.  
  570.   if (x + xadd < 0 || x + xadd >= WIDTH ||
  571.     y + yadd < 0 || y + yadd >= HEIGHT)
  572.     return 0;
  573.   piece = pieces[y + yadd][x + xadd];
  574.   if (piece == 0)
  575.     return 0;
  576.   memcpy(newpieces, pieces, HEIGHT * WIDTH);
  577.   for (l = 0; l < WIDTH; l++) {
  578.     for (m = 0; m < HEIGHT; m++) {
  579.       if (newpieces[m][l] == piece)
  580.         newpieces[m][l] = 0;
  581.     }
  582.   }
  583.   xadd = -xadd;
  584.   yadd = -yadd;
  585.   for (l = 0; l < WIDTH; l++) {
  586.     for (m = 0; m < HEIGHT; m++) {
  587.       if (pieces[m][l] == piece) {
  588.         int newx, newy;
  589.  
  590.         newx = l + xadd;
  591.         newy = m + yadd;
  592.         if (newx < 0 || newx >= WIDTH ||
  593.           newy < 0 || newy >= HEIGHT)
  594.           return 0;
  595.         if (newpieces[newy][newx] != 0)
  596.           return 0;
  597.         newpieces[newy][newx] = piece;
  598.       }
  599.     }
  600.   }
  601.   return 1;
  602. }
  603.  
  604. /* Checks if a piece can move */
  605. int
  606. canmove(Config pieces, int x, int y, int dir, Config newpieces)
  607. {
  608.   int xadd, yadd;
  609.  
  610.   xadd = xadds[dir];
  611.   yadd = yadds[dir];
  612.  
  613.   if (x + xadd < 0 || x + xadd >= WIDTH ||
  614.     y + yadd < 0 || y + yadd >= HEIGHT)
  615.     return 0;
  616.   if (pieces[y + yadd][x + xadd] == pieces[y][x]) {
  617.     return canmove(pieces, x + xadd, y + yadd, dir, newpieces);
  618.   }
  619.   if (pieces[y + yadd][x + xadd] != 0)
  620.     return 0;
  621.   return canmove0(pieces, x + xadd, y + yadd, (dir + 2) % 4, newpieces);
  622. }
  623.  
  624. int
  625. generateNewConfigs(struct puzzle *puzzle)
  626. {
  627.   int i, j, k;
  628.   Config pieces;
  629.   Config newpieces;
  630.  
  631.   memcpy(pieces, puzzle->pieces, HEIGHT * WIDTH);
  632.   for (i = 0; i < WIDTH; i++) {
  633.     for (j = 0; j < HEIGHT; j++) {
  634.       if (pieces[j][i] == 0) {
  635.         for (k = 0; k < 4; k++) {
  636.           if (canmove0(pieces, i, j, k, newpieces)) {
  637.             if (addConfig(newpieces, puzzle))
  638.               return 1;
  639.           }
  640.         }
  641.       }
  642.     }
  643.   }
  644.   return 0;
  645. }
  646.  
  647. void
  648. freeSolutions(void)
  649. {
  650.   struct puzzlelist *nextpuz;
  651.   struct puzzle *puzzle, *next;
  652.   int i;
  653.  
  654.   while (puzzles) {
  655.     nextpuz = puzzles->next;
  656.     free((char *) puzzles);
  657.     puzzles = nextpuz;
  658.   }
  659.   lastentry = NULL;
  660.   for (i = 0; i < HASHSIZE; i++) {
  661.     puzzle = hashtable[i];
  662.     hashtable[i] = NULL;
  663.     while (puzzle) {
  664.       next = puzzle->next;
  665.       free((char *) puzzle);
  666.       puzzle = next;
  667.     }
  668.   }
  669.   startPuzzle = NULL;
  670. }
  671.  
  672. int
  673. continueSolving(void)
  674. {
  675.   struct puzzle *nextpuz;
  676.   int i, j;
  677.   int movedPiece;
  678.   int movedir;
  679.   int fromx, fromy;
  680.   int tox, toy;
  681.  
  682.   if (startPuzzle == NULL)
  683.     return 0;
  684.   if (startPuzzle->solnptr == NULL) {
  685.     freeSolutions();
  686.     return 0;
  687.   }
  688.   nextpuz = startPuzzle->solnptr;
  689.   movedPiece = 0;
  690.   movedir = 0;
  691.   for (i = 0; i < HEIGHT; i++) {
  692.     for (j = 0; j < WIDTH; j++) {
  693.       if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
  694.         if (startPuzzle->pieces[i][j]) {
  695.           movedPiece = startPuzzle->pieces[i][j];
  696.           fromx = j;
  697.           fromy = i;
  698.           if (i < HEIGHT - 1 && nextpuz->pieces[i + 1][j] == movedPiece) {
  699.             movedir = 3;
  700.           } else {
  701.             movedir = 2;
  702.           }
  703.           goto found_piece;
  704.         } else {
  705.           movedPiece = nextpuz->pieces[i][j];
  706.           if (i < HEIGHT - 1 &&
  707.             startPuzzle->pieces[i + 1][j] == movedPiece) {
  708.             fromx = j;
  709.             fromy = i + 1;
  710.             movedir = 1;
  711.           } else {
  712.             fromx = j + 1;
  713.             fromy = i;
  714.             movedir = 0;
  715.           }
  716.           goto found_piece;
  717.         }
  718.       }
  719.     }
  720.   }
  721.   glutSetWindowTitle("What!  No change?");
  722.   freeSolutions();
  723.   return 0;
  724.  
  725. found_piece:
  726.   if (!movingPiece) {
  727.     movingPiece = movedPiece;
  728.     move_x = fromx;
  729.     move_y = fromy;
  730.   }
  731.   move_x += xadds[movedir] * MOVE_SPEED;
  732.   move_y += yadds[movedir] * MOVE_SPEED;
  733.  
  734.   tox = fromx + xadds[movedir];
  735.   toy = fromy + yadds[movedir];
  736.  
  737.   if (move_x > tox - MOVE_SPEED / 2 && move_x < tox + MOVE_SPEED / 2 &&
  738.     move_y > toy - MOVE_SPEED / 2 && move_y < toy + MOVE_SPEED / 2) {
  739.     startPuzzle = nextpuz;
  740.     movingPiece = 0;
  741.   }
  742.   memcpy(thePuzzle, startPuzzle->pieces, HEIGHT * WIDTH);
  743.   changeState();
  744.   return 1;
  745. }
  746.  
  747. int
  748. solvePuzzle(void)
  749. {
  750.   struct puzzlelist *nextpuz;
  751.   char buf[256];
  752.   int i;
  753.  
  754.   if (solution(thePuzzle)) {
  755.     glutSetWindowTitle("Puzzle already solved!");
  756.     return 0;
  757.   }
  758.   addConfig(thePuzzle, NULL);
  759.   i = 0;
  760.  
  761.   while (puzzles) {
  762.     i++;
  763.     if (generateNewConfigs(puzzles->puzzle))
  764.       break;
  765.     nextpuz = puzzles->next;
  766.     free((char *) puzzles);
  767.     puzzles = nextpuz;
  768.   }
  769.   if (puzzles == NULL) {
  770.     freeSolutions();
  771.     sprintf(buf, "I can't solve it! (%d positions examined)", i);
  772.     glutSetWindowTitle(buf);
  773.     return 1;
  774.   }
  775.   return 1;
  776. }
  777.  
  778. int
  779. selectPiece(int mousex, int mousey)
  780. {
  781.   long hits;
  782.   GLuint selectBuf[1024];
  783.   GLuint closest;
  784.   GLuint dist;
  785.  
  786.   glSelectBuffer(1024, selectBuf);
  787.   (void) glRenderMode(GL_SELECT);
  788.   glInitNames();
  789.  
  790.   /* Because LoadName() won't work with no names on the stack */
  791.   glPushName(0);
  792.  
  793.   glMatrixMode(GL_PROJECTION);
  794.   glLoadIdentity();
  795.   gluPickMatrix(mousex, H - mousey, 4, 4, viewport);
  796.   gluPerspective(45, viewport[2]*1.0/viewport[3], 0.1, 100.0);
  797.  
  798.   drawAll();
  799.  
  800.   hits = glRenderMode(GL_RENDER);
  801.   if (hits <= 0) {
  802.     return 0;
  803.   }
  804.   closest = 0;
  805.   dist = 0xFFFFFFFFU; //2147483647;
  806.   while (hits) {
  807.     if (selectBuf[(hits - 1) * 4 + 1] < dist) {
  808.       dist = selectBuf[(hits - 1) * 4 + 1];
  809.       closest = selectBuf[(hits - 1) * 4 + 3];
  810.     }
  811.     hits--;
  812.   }
  813.   return closest;
  814. }
  815.  
  816. void
  817. nukePiece(int piece)
  818. {
  819.   int i, j;
  820.  
  821.   for (i = 0; i < HEIGHT; i++) {
  822.     for (j = 0; j < WIDTH; j++) {
  823.       if (thePuzzle[i][j] == piece) {
  824.         thePuzzle[i][j] = 0;
  825.       }
  826.     }
  827.   }
  828. }
  829.  
  830. void
  831. multMatrices(const GLfloat a[16], const GLfloat b[16], GLfloat r[16])
  832. {
  833.   int i, j;
  834.  
  835.   for (i = 0; i < 4; i++) {
  836.     for (j = 0; j < 4; j++) {
  837.       r[i * 4 + j] =
  838.         a[i * 4 + 0] * b[0 * 4 + j] +
  839.         a[i * 4 + 1] * b[1 * 4 + j] +
  840.         a[i * 4 + 2] * b[2 * 4 + j] +
  841.         a[i * 4 + 3] * b[3 * 4 + j];
  842.     }
  843.   }
  844. }
  845.  
  846. void
  847. makeIdentity(GLfloat m[16])
  848. {
  849.   m[0 + 4 * 0] = 1;
  850.   m[0 + 4 * 1] = 0;
  851.   m[0 + 4 * 2] = 0;
  852.   m[0 + 4 * 3] = 0;
  853.   m[1 + 4 * 0] = 0;
  854.   m[1 + 4 * 1] = 1;
  855.   m[1 + 4 * 2] = 0;
  856.   m[1 + 4 * 3] = 0;
  857.   m[2 + 4 * 0] = 0;
  858.   m[2 + 4 * 1] = 0;
  859.   m[2 + 4 * 2] = 1;
  860.   m[2 + 4 * 3] = 0;
  861.   m[3 + 4 * 0] = 0;
  862.   m[3 + 4 * 1] = 0;
  863.   m[3 + 4 * 2] = 0;
  864.   m[3 + 4 * 3] = 1;
  865. }
  866.  
  867. /*
  868.    ** inverse = invert(src)
  869.  */
  870. int
  871. invertMatrix(const GLfloat src[16], GLfloat inverse[16])
  872. {
  873.   int i, j, k, swap;
  874.   double t;
  875.   GLfloat temp[4][4];
  876.  
  877.   for (i = 0; i < 4; i++) {
  878.     for (j = 0; j < 4; j++) {
  879.       temp[i][j] = src[i * 4 + j];
  880.     }
  881.   }
  882.   makeIdentity(inverse);
  883.  
  884.   for (i = 0; i < 4; i++) {
  885.     /* 
  886.        ** Look for largest element in column */
  887.     swap = i;
  888.     for (j = i + 1; j < 4; j++) {
  889.       if (fabs(temp[j][i]) > fabs(temp[i][i])) {
  890.         swap = j;
  891.       }
  892.     }
  893.  
  894.     if (swap != i) {
  895.       /* 
  896.          ** Swap rows. */
  897.       for (k = 0; k < 4; k++) {
  898.         t = temp[i][k];
  899.         temp[i][k] = temp[swap][k];
  900.         temp[swap][k] = t;
  901.  
  902.         t = inverse[i * 4 + k];
  903.         inverse[i * 4 + k] = inverse[swap * 4 + k];
  904.         inverse[swap * 4 + k] = t;
  905.       }
  906.     }
  907.     if (temp[i][i] == 0) {
  908.       /* 
  909.          ** No non-zero pivot.  The matrix is singular, which
  910.          shouldn't ** happen.  This means the user gave us a
  911.          bad matrix. */
  912.       return 0;
  913.     }
  914.     t = temp[i][i];
  915.     for (k = 0; k < 4; k++) {
  916.       temp[i][k] /= t;
  917.       inverse[i * 4 + k] /= t;
  918.     }
  919.     for (j = 0; j < 4; j++) {
  920.       if (j != i) {
  921.         t = temp[j][i];
  922.         for (k = 0; k < 4; k++) {
  923.           temp[j][k] -= temp[i][k] * t;
  924.           inverse[j * 4 + k] -= inverse[i * 4 + k] * t;
  925.         }
  926.       }
  927.     }
  928.   }
  929.   return 1;
  930. }
  931.  
  932. /*
  933.    ** This is a screwball function.  What it does is the following:
  934.    ** Given screen x and y coordinates, compute the corresponding object space 
  935.    **   x and y coordinates given that the object space z is 0.9 + OFFSETZ.
  936.    ** Since the tops of (most) pieces are at z = 0.9 + OFFSETZ, we use that 
  937.    **   number.
  938.  */
  939. int
  940. computeCoords(int piece, int mousex, int mousey,
  941.   GLfloat * selx, GLfloat * sely)
  942. {
  943.   GLfloat modelMatrix[16];
  944.   GLfloat projMatrix[16];
  945.   GLfloat finalMatrix[16];
  946.   GLfloat in[4];
  947.   GLfloat a, b, c, d;
  948.   GLfloat top, bot;
  949.   GLfloat z;
  950.   GLfloat w;
  951.   GLfloat height;
  952.  
  953.   if (piece == 0)
  954.     return 0;
  955.   height = zsize[piece] - 0.1 + OFFSETZ;
  956.  
  957.   glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
  958.   glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
  959.   multMatrices(modelMatrix, projMatrix, finalMatrix);
  960.   if (!invertMatrix(finalMatrix, finalMatrix))
  961.     return 0;
  962.  
  963.   in[0] = (2.0 * (mousex - viewport[0]) / viewport[2]) - 1;
  964.   in[1] = (2.0 * ((H - mousey) - viewport[1]) / viewport[3]) - 1;
  965.  
  966.   a = in[0] * finalMatrix[0 * 4 + 2] +
  967.     in[1] * finalMatrix[1 * 4 + 2] +
  968.     finalMatrix[3 * 4 + 2];
  969.   b = finalMatrix[2 * 4 + 2];
  970.   c = in[0] * finalMatrix[0 * 4 + 3] +
  971.     in[1] * finalMatrix[1 * 4 + 3] +
  972.     finalMatrix[3 * 4 + 3];
  973.   d = finalMatrix[2 * 4 + 3];
  974.  
  975.   /* 
  976.      ** Ok, now we need to solve for z: **   (a + b z) / (c + d 
  977.  
  978.      z) = height. ** ("height" is the height in object space we 
  979.  
  980.      want to solve z for) ** ** ==>  a + b z = height c +
  981.      height d z **      bz - height d z = height c - a ** z =
  982.      (height c - a) / (b - height d) */
  983.   top = height * c - a;
  984.   bot = b - height * d;
  985.   if (bot == 0.0)
  986.     return 0;
  987.  
  988.   z = top / bot;
  989.  
  990.   /* 
  991.      ** Ok, no problem. ** Now we solve for x and y.  We know
  992.      that w = c + d z, so we compute it. */
  993.   w = c + d * z;
  994.  
  995.   /* 
  996.      ** Now for x and y: */
  997.   *selx = (in[0] * finalMatrix[0 * 4 + 0] +
  998.     in[1] * finalMatrix[1 * 4 + 0] +
  999.     z * finalMatrix[2 * 4 + 0] +
  1000.     finalMatrix[3 * 4 + 0]) / w - OFFSETX;
  1001.   *sely = (in[0] * finalMatrix[0 * 4 + 1] +
  1002.     in[1] * finalMatrix[1 * 4 + 1] +
  1003.     z * finalMatrix[2 * 4 + 1] +
  1004.     finalMatrix[3 * 4 + 1]) / w - OFFSETY;
  1005.   return 1;
  1006. }
  1007.  
  1008. static int selected;
  1009. static int selectx, selecty;
  1010. static float selstartx, selstarty;
  1011.  
  1012. void
  1013. grabPiece(int piece, float selx, float sely)
  1014. {
  1015.   int hit;
  1016.  
  1017.   selectx = int(selx);
  1018.   selecty = int(sely);
  1019.   if (selectx < 0 || selecty < 0 || selectx >= WIDTH || selecty >= HEIGHT) {
  1020.     return;
  1021.   }
  1022.   hit = thePuzzle[selecty][selectx];
  1023.   if (hit != piece)
  1024.     return;
  1025.   if (hit) {
  1026.     movingPiece = hit;
  1027.     while (selectx > 0 && thePuzzle[selecty][selectx - 1] == movingPiece) {
  1028.       selectx--;
  1029.     }
  1030.     while (selecty > 0 && thePuzzle[selecty - 1][selectx] == movingPiece) {
  1031.       selecty--;
  1032.     }
  1033.     move_x = selectx;
  1034.     move_y = selecty;
  1035.     selected = 1;
  1036.     selstartx = selx;
  1037.     selstarty = sely;
  1038.   } else {
  1039.     selected = 0;
  1040.   }
  1041.   changeState();
  1042. }
  1043.  
  1044. void
  1045. moveSelection(float selx, float sely)
  1046. {
  1047.   float deltax, deltay;
  1048.   int dir;
  1049.   Config newpieces;
  1050.  
  1051.   if (!selected)
  1052.     return;
  1053.   deltax = selx - selstartx;
  1054.   deltay = sely - selstarty;
  1055.  
  1056.   if (fabs(deltax) > fabs(deltay)) {
  1057.     deltay = 0;
  1058.     if (deltax > 0) {
  1059.       if (deltax > 1)
  1060.         deltax = 1;
  1061.       dir = 2;
  1062.     } else {
  1063.       if (deltax < -1)
  1064.         deltax = -1;
  1065.       dir = 0;
  1066.     }
  1067.   } else {
  1068.     deltax = 0;
  1069.     if (deltay > 0) {
  1070.       if (deltay > 1)
  1071.         deltay = 1;
  1072.       dir = 3;
  1073.     } else {
  1074.       if (deltay < -1)
  1075.         deltay = -1;
  1076.       dir = 1;
  1077.     }
  1078.   }
  1079.   if (canmove(thePuzzle, selectx, selecty, dir, newpieces)) {
  1080.     move_x = deltax + selectx;
  1081.     move_y = deltay + selecty;
  1082.     if (deltax > 0.5) {
  1083.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1084.       selectx++;
  1085.       selstartx++;
  1086.     } else if (deltax < -0.5) {
  1087.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1088.       selectx--;
  1089.       selstartx--;
  1090.     } else if (deltay > 0.5) {
  1091.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1092.       selecty++;
  1093.       selstarty++;
  1094.     } else if (deltay < -0.5) {
  1095.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1096.       selecty--;
  1097.       selstarty--;
  1098.     }
  1099.   } else {
  1100.     if (deltay > 0 && thePuzzle[selecty][selectx] == 10 &&
  1101.       selectx == 1 && selecty == 3) {
  1102.       /* Allow visual movement of solution piece outside of the 
  1103.  
  1104.          box */
  1105.       move_x = selectx;
  1106.       move_y = sely - selstarty + selecty;
  1107.     } else {
  1108.       move_x = selectx;
  1109.       move_y = selecty;
  1110.     }
  1111.   }
  1112. }
  1113.  
  1114. void
  1115. dropSelection(void)
  1116. {
  1117.   if (!selected)
  1118.     return;
  1119.   movingPiece = 0;
  1120.   selected = 0;
  1121.   changeState();
  1122. }
  1123.  
  1124. static int left_mouse, middle_mouse;
  1125. static int mousex, mousey;
  1126. static int solving;
  1127. static int spinning;
  1128. static float lastquat[4];
  1129. static int sel_piece;
  1130.  
  1131. static void
  1132. Reshape(int width, int height)
  1133. {
  1134.  
  1135.   W = width;
  1136.   H = height;
  1137.   glViewport(0, 0, W, H);
  1138.   glGetIntegerv(GL_VIEWPORT, viewport);
  1139. }
  1140.  
  1141. void
  1142. toggleSolve(void)
  1143. {
  1144.     if (solving) {
  1145.       freeSolutions();
  1146.       solving = 0;
  1147.       glutChangeToMenuEntry(1, "Solving", 1);
  1148.       glutSetWindowTitle("glpuzzle");
  1149.       movingPiece = 0;
  1150.     } else {
  1151.       glutChangeToMenuEntry(1, "Stop solving", 1);
  1152.       glutSetWindowTitle("Solving...");
  1153.       if (solvePuzzle()) {
  1154.         solving = 1;
  1155.       }
  1156.     }
  1157.     changeState();
  1158.     glutPostRedisplay();
  1159. }
  1160.  
  1161. void reset(void)
  1162. {
  1163.     if (solving) {
  1164.       freeSolutions();
  1165.       solving = 0;
  1166.       glutChangeToMenuEntry(1, "Solving", 1);
  1167.       glutSetWindowTitle("glpuzzle");
  1168.       movingPiece = 0;
  1169.       changeState();
  1170.     }
  1171.     memcpy(thePuzzle, startConfig, HEIGHT * WIDTH);
  1172.     glutPostRedisplay();
  1173. }
  1174.  
  1175. void
  1176. keyboard(unsigned char c, int x, int y)
  1177. {
  1178.   int piece;
  1179.  
  1180.   switch (c) {
  1181.   case 27:
  1182.     exit(0);
  1183.     break;
  1184.   case 'D':
  1185.   case 'd':
  1186.     if (solving) {
  1187.       freeSolutions();
  1188.       solving = 0;
  1189.       glutChangeToMenuEntry(1, "Solving", 1);
  1190.       glutSetWindowTitle("glpuzzle");
  1191.       movingPiece = 0;
  1192.       changeState();
  1193.     }
  1194.     piece = selectPiece(x, y);
  1195.     if (piece) {
  1196.       nukePiece(piece);
  1197.     }
  1198.     glutPostRedisplay();
  1199.     break;
  1200.   case 'R':
  1201.   case 'r':
  1202.     reset();
  1203.     break;
  1204.   case 'S':
  1205.   case 's':
  1206.     toggleSolve();
  1207.     break;
  1208.   case 'b':
  1209.   case 'B':
  1210.     depth = 1 - depth;
  1211.     if (depth) {
  1212.       glEnable(GL_DEPTH_TEST);
  1213.     } else {
  1214.       glDisable(GL_DEPTH_TEST);
  1215.     }
  1216.     glutPostRedisplay();
  1217.     break;
  1218.   default:
  1219.     break;
  1220.   }
  1221. }
  1222.  
  1223. void
  1224. motion(int x, int y)
  1225. {
  1226.   float selx, sely;
  1227.  
  1228.   if (middle_mouse && !left_mouse) {
  1229.     if (mousex != x || mousey != y) {
  1230.       trackball(lastquat,
  1231.         (2.0*mousex - W) / W,
  1232.         (H - 2.0*mousey) / H,
  1233.         (2.0*x - W) / W,
  1234.         (H - 2.0*y) / H);
  1235.       spinning = 1;
  1236.     } else {
  1237.       spinning = 0;
  1238.     }
  1239.     changeState();
  1240.   } else {
  1241.     computeCoords(sel_piece, x, y, &selx, &sely);
  1242.     moveSelection(selx, sely);
  1243.   }
  1244.   mousex = x;
  1245.   mousey = y;
  1246.   glutPostRedisplay();
  1247. }
  1248.  
  1249. void
  1250. mouse(int b, int s, int x, int y)
  1251. {
  1252.   float selx, sely;
  1253.  
  1254.   mousex = x;
  1255.   mousey = y;
  1256.   curX = x;
  1257.   curY = y;
  1258.   if (s == GLUT_DOWN) {
  1259.     switch (b) {
  1260.     case GLUT_LEFT_BUTTON:
  1261.       if (solving) {
  1262.         freeSolutions();
  1263.         solving = 0;
  1264.       glutChangeToMenuEntry(1, "Solving", 1);
  1265.         glutSetWindowTitle("glpuzzle");
  1266.         movingPiece = 0;
  1267.       }
  1268.       left_mouse = GL_TRUE;
  1269.       sel_piece = selectPiece(mousex, mousey);
  1270.       if (!sel_piece) {
  1271.       left_mouse = GL_FALSE;
  1272.       middle_mouse = GL_TRUE; // let it rotate object
  1273.       } else if (computeCoords(sel_piece, mousex, mousey, &selx, &sely)) {
  1274.         grabPiece(sel_piece, selx, sely);
  1275.       }
  1276.       glutPostRedisplay();
  1277.       break;
  1278.     case GLUT_MIDDLE_BUTTON:
  1279.       middle_mouse = GL_TRUE;
  1280.       glutPostRedisplay();
  1281.       break;
  1282.     }
  1283.   } else {
  1284.     if (left_mouse) {
  1285.       left_mouse = GL_FALSE;
  1286.       dropSelection();
  1287.       glutPostRedisplay();
  1288.     } else if (middle_mouse) {
  1289.       middle_mouse = GL_FALSE;
  1290.       glutPostRedisplay();
  1291.     }
  1292.   }
  1293.   motion(x, y);
  1294. }
  1295.  
  1296. void
  1297. animate(void)
  1298. {
  1299.   if (spinning) {
  1300.     add_quats(lastquat, curquat, curquat);
  1301.   }
  1302.   glutPostRedisplay();
  1303.   if (solving) {
  1304.     if (!continueSolving()) {
  1305.       solving = 0;
  1306.       glutChangeToMenuEntry(1, "Solving", 1);
  1307.       glutSetWindowTitle("glpuzzle");
  1308.     }
  1309.   }
  1310.   if (!solving && !spinning && !visible) {
  1311.     glutIdleFunc(NULL);
  1312.   }
  1313. }
  1314.  
  1315. void
  1316. changeState(void)
  1317. {
  1318.   if (visible) {
  1319.     if (!solving && !spinning) {
  1320.       glutIdleFunc(NULL);
  1321.     } else {
  1322.       glutIdleFunc(animate);
  1323.     }
  1324.   } else {
  1325.     glutIdleFunc(NULL);
  1326.   }
  1327. }
  1328.  
  1329. void
  1330. init(void)
  1331. {
  1332.   static float lmodel_ambient[] =
  1333.   {0.0, 0.0, 0.0, 0.0};
  1334.   static float lmodel_twoside[] =
  1335.   {GL_FALSE};
  1336.   static float lmodel_local[] =
  1337.   {GL_FALSE};
  1338.   static float light0_ambient[] =
  1339.   {0.1, 0.1, 0.1, 1.0};
  1340.   static float light0_diffuse[] =
  1341.   {1.0, 1.0, 1.0, 0.0};
  1342.   static float light0_position[] =
  1343.   {0.8660254, 0.5, 1, 0};
  1344.   static float light0_specular[] =
  1345.   {0.0, 0.0, 0.0, 0.0};
  1346.   static float bevel_mat_ambient[] =
  1347.   {0.0, 0.0, 0.0, 1.0};
  1348.   static float bevel_mat_shininess[] =
  1349.   {40.0};
  1350.   static float bevel_mat_specular[] =
  1351.   {0.0, 0.0, 0.0, 0.0};
  1352.   static float bevel_mat_diffuse[] =
  1353.   {1.0, 0.0, 0.0, 0.0};
  1354.  
  1355.   glEnable(GL_CULL_FACE);
  1356.   glCullFace(GL_BACK);
  1357.   glEnable(GL_DEPTH_TEST);
  1358.   glClearDepth(1.0);
  1359.  
  1360.   glClearColor(0.5, 0.5, 0.5, 0.0);
  1361.   glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  1362.   glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  1363.   glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
  1364.   glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
  1365.   glEnable(GL_LIGHT0);
  1366.  
  1367.   glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local);
  1368.   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
  1369.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  1370.   glEnable(GL_LIGHTING);
  1371.  
  1372.   glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient);
  1373.   glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess);
  1374.   glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular);
  1375.   glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse);
  1376.  
  1377.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  1378.   glEnable(GL_COLOR_MATERIAL);
  1379.   glShadeModel(GL_FLAT);
  1380.  
  1381.   trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  1382.   srandom(time(NULL));
  1383. }
  1384.  
  1385. static void
  1386. Usage(void)
  1387. {
  1388.   printf("Usage: puzzle [-s]\n");
  1389.   printf("   -s:  Run in single buffered mode\n");
  1390.   exit(-1);
  1391. }
  1392.  
  1393. void
  1394. visibility(int v)
  1395. {
  1396.   if (v == GLUT_VISIBLE) {
  1397.     visible = 1;
  1398.   } else {
  1399.     visible = 0;
  1400.   }
  1401.   changeState();
  1402. }
  1403.  
  1404. void
  1405. menu(int choice)
  1406. {
  1407.    switch(choice) {
  1408.    case 1:
  1409.       toggleSolve();
  1410.       break;
  1411.    case 2:
  1412.       reset();
  1413.       break;
  1414.    case 3:
  1415.       exit(0);
  1416.       break;
  1417.    }
  1418. }
  1419.  
  1420. int
  1421. main(int argc, char **argv)
  1422. {
  1423.   long i;
  1424.  
  1425.   glutInit(&argc, argv);
  1426.   for (i = 1; i < argc; i++) {
  1427.     if (argv[i][0] == '-') {
  1428.       switch (argv[i][1]) {
  1429.       case 's':
  1430.         doubleBuffer = 0;
  1431.         break;
  1432.       default:
  1433.         Usage();
  1434.       }
  1435.     } else {
  1436.       Usage();
  1437.     }
  1438.   }
  1439.  
  1440.   glutInitWindowSize(W, H);
  1441.   if (doubleBuffer) {
  1442.     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
  1443.   } else {
  1444.     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE | GLUT_MULTISAMPLE);
  1445.   }
  1446.  
  1447.   glutCreateWindow("glpuzzle");
  1448.   visible = 1; // added for fltk, bug in original program?
  1449.  
  1450.   init();
  1451.  
  1452.   glGetIntegerv(GL_VIEWPORT, viewport);
  1453.  
  1454.   printf("\n");
  1455.   printf("r   Reset puzzle\n");
  1456.   printf("s   Solve puzzle (may take a few seconds to compute)\n");
  1457.   printf("d   Destroy a piece - makes the puzzle easier\n");
  1458.   printf("b   Toggles the depth buffer on and off\n");
  1459.   printf("\n");
  1460.   printf("Left mouse moves pieces\n");
  1461.   printf("Middle mouse spins the puzzle\n");
  1462.   printf("Right mouse has menu\n");
  1463.  
  1464.   glutReshapeFunc(Reshape);
  1465.   glutDisplayFunc(redraw);
  1466.   glutKeyboardFunc(keyboard);
  1467.   glutMotionFunc(motion);
  1468.   glutMouseFunc(mouse);
  1469.   glutVisibilityFunc(visibility);
  1470.   glutCreateMenu(menu);
  1471.   glutAddMenuEntry("Solve", 1);
  1472.   glutAddMenuEntry("Reset", 2);
  1473.   glutAddMenuEntry("Quit", 3);
  1474.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  1475.   glutMainLoop();
  1476.   return 0;             /* ANSI C requires main to return int. */
  1477. }
  1478.  
  1479. #endif // added for fltk's distribution
  1480.  
  1481. //
  1482. // End of "$Id: glpuzzle.cxx,v 1.8 1999/02/25 20:05:30 bill Exp $".
  1483. //
  1484.